package com.ushine.web.component.authority.handler;

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.ushine.web.base.model.redis.UserRedisBO;
import com.ushine.web.base.model.system.DataPermissionDO;
import com.ushine.web.base.facade.IUserRedisFacade;
import com.ushine.web.component.authority.utils.DataColumnUtils;
import com.ushine.web.component.exception.ServiceException;
import com.ushine.web.component.exception.ServiceExceptionEnum;
import com.ushine.web.security.utils.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.persistence.Column;
import java.lang.reflect.Field;
import java.util.Map;

/**
 * @Author: yls
 * @Date: 2022/02/24 09:32
 * @Description: 数据权限：数据更新控制器
 * @Version 1.0
 */
@Slf4j
@Component
public class UpdateDataPermissionHandler {

    @Resource
    private IUserRedisFacade userRedisFacade;

    /**
     * 功能描述:
     * 〈 修改时的字段过滤：
     * 修改数据时：如果需要数据权限，是通过指定字段更新完成修改时的列级权限控制
     * 返回null：如果没有设置该用户的列级权限，就会返回null，调用方需要判断，如果为null，直接更新实体obj
     * 〉
     *
     * @param obj                修改对象
     * @param dataPermissionFlag 权限标识
     * @return : T 如何返回null的时候请更新整个实体
     * @throws ServiceException 服务端自定义异常
     * @author : yls
     * @date : 2022/02/24 11:16
     */
    public <T> UpdateWrapper<T> getUpdateDataWrapper(T obj, String dataPermissionFlag) throws ServiceException {
        /*
         * 获取当前用户拥有的列级权限
         */
        String username = SecurityUtils.getUsername();
        UserRedisBO userInfo = userRedisFacade.getUserInfo(username);
        DataPermissionDO dataPermission = userInfo.getDataPermissionMap().get(dataPermissionFlag);
        // 没有设置数据权限，默认任务拥有【所有列】的【添加】数据权限
        if (dataPermission == null) {
            // 返回null的时候就不做数据权限
            return null;
        }
        // 获取列权限
        // 过滤列（不包含这些列）
        String dataColumnExclude = dataPermission.getDataColumnExclude();
        Map<String, Integer> excludeColumnMap = DataColumnUtils.getColumnSetByString(dataColumnExclude);
        // 包含列（只有这些列权限）
        String dataColumnInclude = dataPermission.getDataColumnInclude();
        Map<String, Integer> includeColumnMap = DataColumnUtils.getColumnSetByString(dataColumnInclude);

        if (excludeColumnMap.isEmpty() && includeColumnMap.isEmpty()) {
            // 返回null的时候就不做数据权限
            return null;
        }

        /*
         * 遍历实体的字段
         */
        UpdateWrapper<T> updateWrapper;
        try {
            updateWrapper = getUpdateWrapper(obj, excludeColumnMap, includeColumnMap);
        } catch (Exception e) {
            log.error("数据权限：更新数据过滤字段异常！", e);
            throw new ServiceException(ServiceExceptionEnum.DATA_PERMISSION_UPDATE_ERROR, e);
        }
        return updateWrapper;
    }

    /**
     * 功能描述:
     * 〈 获取更新的条件 〉
     *
     * @param obj              对象
     * @param excludeColumnMap 不包括的字段列表
     * @param includeColumnMap 包括的字段列表
     * @return : com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper<T>
     * @author : yls
     * @date : 2022/02/24 11:43
     */
    public <T> UpdateWrapper<T> getUpdateWrapper(T obj, Map<String, Integer> excludeColumnMap, Map<String, Integer> includeColumnMap) throws IllegalAccessException {
        UpdateWrapper<T> updateWrapper = new UpdateWrapper<>();
        Class<?> aClass = obj.getClass();
        Field[] declaredFields = aClass.getDeclaredFields();
        for (Field field :
                declaredFields) {
            String name = field.getName();
            if ("id".equals(name)) {
                // 设置取消属性访问检查，可以访问私有属性
                field.setAccessible(true);
                updateWrapper.eq("id", field.get(obj));
            }
            // 系统后台自带字段不参加过滤
            boolean flag = DataColumnUtils.EXCLUDE_COLUMN_MAP.containsKey(name)
                    || (!excludeColumnMap.isEmpty() && excludeColumnMap.containsKey(name));
            if (Boolean.TRUE.equals(flag)) {
                continue;
            }
            // 先过滤不包含字段
            if (!excludeColumnMap.isEmpty() && !excludeColumnMap.containsKey(name)) {
                Column annotation = field.getAnnotation(Column.class);
                String columnName = annotation.name();
                // 设置取消属性访问检查，可以访问私有属性
                field.setAccessible(true);
                updateWrapper.set(columnName, field.get(obj));
            }


            // 开始处理权限访问字段
            if (!includeColumnMap.isEmpty() && includeColumnMap.containsKey(name)) {
                Column annotation = field.getAnnotation(Column.class);
                String columnName = annotation.name();
                // 设置取消属性访问检查，可以访问私有属性
                field.setAccessible(true);
                updateWrapper.set(columnName, field.get(obj));
            }

        }
        return updateWrapper;
    }
}
